#include "public_def.h"
#include "base64.h"

static char g_cBase64Tab[2][65] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
                                   "abcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZ"};

static char g_cDecBase64Tab[2][128] = {{64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
                                        64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
                                        64,64,64,62,64,64,64,63,52,53,54,55,56,57,58,59,60,61,64,64,
                                        64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,
                                        18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,28,29,30,31,
                                        32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
                                        64,64,64,64,64},
                                        {64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
                                        64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
                                        64,64,64,36,64,64,64,37,26,27,28,29,30,31,32,33,34,35,64,64,
                                        64,64,64,64,64,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
                                        53,54,55,56,57,58,59,60,61,62,63,64,64,64,64,64,64,0,1,2,3,
                                        4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,
                                        64,64,64,64,64}};

#if 0
static unsigned char FindInTable(unsigned char c, int _iStdFlg)
{
    int i = 0;
    char *pcBase64Tab = _iStdFlg ? g_cBase64Tab[0] : g_cBase64Tab[1];
    
    for(i = 0; i < 64; i++)
    {
        if(pcBase64Tab[i] == c)
        {
            return i;
        }
    }
    
	return 0;
}

static void MakeBase64DecodeTab()
{
    int i = 0;
    int j = 0;
    char cDecTab[128] = {'0'};
    int iFlg = 0;

    memset(cDecTab, 0, sizeof(cDecTab));

    for (i = 0; i < 128; i++)
    {
        iFlg = 0;
        for (j = 0; j < 64; j++)
        {
            if (i == g_cBase64Tab[0][j])
            {
                iFlg = 1;
                break;
            }
        }

        if (iFlg)
        {
            cDecTab[i] = j;
        }
        else
        {
            cDecTab[i] = 64;
        }
    }
    
    for (i = 0; i < 128; i++)
    {
        printf("%d,", cDecTab[i]);
    }

    printf("\n\n");
    
    for (i = 0; i < 128; i++)
    {
        iFlg = 0;
        for (j = 0; j < 64; j++)
        {
            if (i == g_cBase64Tab[1][j])
            {
                iFlg = 1;
                break;
            }
        }

        if (iFlg)
        {
            cDecTab[i] = j;
        }
        else
        {
            cDecTab[i] = 64;
        }
    }
    
    for (i = 0; i < 128; i++)
    {
        printf("%d,", cDecTab[i]);
    }
}
#endif

int base64_encodeEx(unsigned char* outputBuf, int* outputLen,
                   unsigned char* inputBuf, int inputLen, int _iStdFlg)
{
    unsigned char c1, c2, c3;
    unsigned char *pOutputBuf = outputBuf;
    int count = 0, charsPerLine = 0;
    char *pcBase64Tab = _iStdFlg ? g_cBase64Tab[0] : g_cBase64Tab[1];

    c1 = 0x00;
    c2 = 0x00;
    c3 = 0x00;

    while (count < inputLen)
    {
        c1 = inputBuf[count++];
        if (count == inputLen)
        {
            c2 = 0x00;
            *pOutputBuf++ = pcBase64Tab[c1 >> 2];
            *pOutputBuf++ = pcBase64Tab[(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4))];
            *pOutputBuf++ = '=';
            *pOutputBuf++ = '=';
        }
        else	// count < inputLen
        {
            c2 = inputBuf[count++];
            if (count == inputLen)
            {
                c3 = 0x00;
                *pOutputBuf++ = pcBase64Tab[c1 >> 2];
                *pOutputBuf++ = pcBase64Tab[(((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4))];
                *pOutputBuf++ = pcBase64Tab[(((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6))];
                *pOutputBuf++ = '=';
            }
            else // count  < inputLen
            {
                c3 = inputBuf[count++];
                *pOutputBuf++ = pcBase64Tab[c1 >> 2];
                *pOutputBuf++ = pcBase64Tab[(((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4))];
                *pOutputBuf++ = pcBase64Tab[(((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6))];
                *pOutputBuf++ = pcBase64Tab[(c3 & 0x3F)];
            }
        }

        charsPerLine += 4;

    } //end while

    *pOutputBuf++ = '\0';

    *outputLen = strlen((char*)outputBuf);

    return *outputLen;
}


int base64_decodeEx(unsigned char* outputBuf, int* outputLen,
                   unsigned char* inputBuf, int inputLen, int _iStdFlg)
{
    unsigned char c1, c2, c3, c4;
    int count = 0;
    int iTab = 0;
    
    if (_iStdFlg)
    {
        iTab = 0;
    }
    else
    {
        iTab = 1;
    }
    
    c1 = *inputBuf++;
    while (c1 != '\0')
    {
        c2 = *inputBuf++;
        c3 = *inputBuf++;
        c4 = *inputBuf++;

        c1 = g_cDecBase64Tab[iTab][c1];
        c2 = g_cDecBase64Tab[iTab][c2];

        outputBuf[count++] = ((c1 << 2) | ((c2 & 0x30) >> 4));

        if (c3 != '=')
        {
            c3 = g_cDecBase64Tab[iTab][c3];
            outputBuf[count++] = (((c2 & 0XF) << 4) | ((c3 & 0x3C) >> 2));

            if (c4 != '=')
            {
                c4 = g_cDecBase64Tab[iTab][c4];
                outputBuf[count++] = (((c3 & 0x03) << 6) | c4);
            }
        }

        c1 = *inputBuf++;
        if (c1 == '\r')
        {
            c1 = *inputBuf++;
            if (c1 == '\n')
                c1 = *inputBuf++;
        }
    }// while c1 != 0
    
    outputBuf[count] = '\0';//xumm add 
    *outputLen = count;

    return count;
}

int base64_decode(unsigned char* outputBuf, unsigned int* outputLen,
                   unsigned char* inputBuf, unsigned int inputLen)
{
    return base64_decodeEx(outputBuf, (int*)outputLen, inputBuf, (int)inputLen, 1);
}


int base64_encode(unsigned char* outputBuf, unsigned int* outputLen,
                   unsigned char* inputBuf, unsigned int inputLen, int _iStdFlg)
{
    return base64_encodeEx(outputBuf, (int*)outputLen, inputBuf, (int)inputLen, 1);
}

